//=======================================================================//
//= Include files.													    =//
//=======================================================================//
#include "Utility.h"
#include "Settings.h"
#include "Debug.h"
#include <wx/settings.h>

//=======================================================================//
//= Marco declare.                                                      =//
//=======================================================================//
#define     ARRAY_SIZE(A)					(sizeof(A)/sizeof(A[0]))

//=======================================================================//
//= Global variable definition.                                         =//
//=======================================================================//
const wxString CONFIG_FILE_PATH =			wxT("../config");
const wxString CONFIG_FILE_EXT_NAME =		wxT("xml");
const wxString CONFIG_FILE_NAME =			wxT("config.xml");
const wxString STARTUP_FILE_NAME =			wxT("startup.xml");

const wxString CommentItems[] =
{
	wxT("No comment"),
	wxT("Comment before data"),
	wxT("Comment after data")
};

const size_t COMMENT_ITEMS_COUNT = ARRAY_SIZE(CommentItems);

//=======================================================================//
//= Function define.										            =//
//=======================================================================//
PanelConfiguration::PanelConfiguration(void)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	m_clsBackground.SetRGB(0x00000000);
	m_clsForeground.SetRGB(0x00FFFFFF);
	m_clsPixelSize.Set(3, 3);
}

PanelConfiguration::PanelConfiguration(const wxXmlNode* pclsXmlNode)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	(void)FromXmlNode(pclsXmlNode);
}

PanelConfiguration::PanelConfiguration(const PanelConfiguration& clsSource)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	m_clsBackground = clsSource.GetBackgroundColour();
	m_clsForeground = clsSource.GetForegroundColour();
	m_clsPixelSize = clsSource.PixelUnitSize();
}

wxXmlNode* PanelConfiguration::CreateXmlNode(void)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	wxXmlNode*				pclsNewNode = new wxXmlNode(wxXML_ELEMENT_NODE, CFG_XML_NODE_NAME_PREVIEWPANEL);
	wxXmlNode*				pclsNewChildNode;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(nullptr != pclsNewNode)
	{
		/* PixelSize node. */
		pclsNewChildNode = new wxXmlNode(pclsNewNode, wxXML_ELEMENT_NODE, CFG_XML_NODE_NAME_PIXEL_SIZE);
		if(nullptr != pclsNewChildNode)
		{
			pclsNewChildNode->AddAttribute(wxT("width"), wxString::Format(wxT("%d"), m_clsPixelSize.GetWidth()));
			pclsNewChildNode->AddAttribute(wxT("height"), wxString::Format(wxT("%d"), m_clsPixelSize.GetHeight()));
		}
		/* Color node. */
		pclsNewChildNode = new wxXmlNode(pclsNewNode, wxXML_ELEMENT_NODE, CFG_XML_NODE_NAME_PIXEL_COLOR);
		if(nullptr != pclsNewChildNode)
		{
			/* Get color RGB value and save as CSS like format(#RRGGBB). */
			pclsNewChildNode->AddAttribute(wxT("foreground"),	wxString::Format(wxT("#%02X%02X%02X"), m_clsForeground.Red(), m_clsForeground.Green(), m_clsForeground.Blue()));
			pclsNewChildNode->AddAttribute(wxT("background"),	wxString::Format(wxT("#%02X%02X%02X"), m_clsBackground.Red(), m_clsBackground.Green(), m_clsBackground.Blue()));
			pclsNewChildNode->AddAttribute(wxT("grid"),			wxString::Format(wxT("#%02X%02X%02X"), m_clsGridround.Red(), m_clsGridround.Green(), m_clsGridround.Blue()));
		}
	}
	return pclsNewNode;
}

bool PanelConfiguration::FromXmlNode(const wxXmlNode* pclsXmlNode)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	wxXmlNode*				pclsChildNode;
	wxString				strReadContent;
	bool					bReturn = true;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(nullptr != pclsXmlNode)
	{
		if(pclsXmlNode->GetName().IsSameAs(CFG_XML_NODE_NAME_PREVIEWPANEL, false))
		{
			/* Start to analyze node. */
			pclsChildNode = pclsXmlNode->GetChildren();
			if(nullptr != pclsChildNode)
			{
				while(nullptr != pclsChildNode)
				{
					if(pclsChildNode->GetName().IsSameAs(CFG_XML_NODE_NAME_PIXEL_SIZE, false))
					{
						int iConvertValue;
						strReadContent = pclsChildNode->GetAttribute(wxT("width"));
						iConvertValue = _wtoi(strReadContent);
						if(iConvertValue < 1)
						{
							/* Pixel unit width cannot less then 1. */
							iConvertValue = 1;
						}
						m_clsPixelSize.SetWidth(iConvertValue);
						DBG_LOG("Read setting of pixel unit width is %d(xml value: %s).", iConvertValue, strReadContent);
						strReadContent = pclsChildNode->GetAttribute(wxT("height"));
						iConvertValue = _wtoi(strReadContent);
						if(iConvertValue < 1)
						{
							/* Pixel unit height cannot less then 1. */
							iConvertValue = 1;
						}
						m_clsPixelSize.SetHeight(iConvertValue);
						DBG_LOG("Read setting of pixel unit height is %d(xml value: %s).", iConvertValue, strReadContent);
					}
					else if(pclsChildNode->GetName().IsSameAs(CFG_XML_NODE_NAME_PIXEL_COLOR, false))
					{
						strReadContent = pclsChildNode->GetAttribute(wxT("foreground"), wxT("#FFFFFF"));
						m_clsForeground.Set(strReadContent);
						DBG_LOG("Read setting of foreground color is %s.", strReadContent);
						strReadContent = pclsChildNode->GetAttribute(wxT("background"), wxT("#000000"));
						m_clsBackground.Set(strReadContent);
						DBG_LOG("Read setting of background color is %s.", strReadContent);
						strReadContent = pclsChildNode->GetAttribute(wxT("grid"), wxT("#000000"));
						m_clsGridround.Set(strReadContent);
						DBG_LOG("Read setting of grid color is %s.", strReadContent);
					}
					pclsChildNode = pclsChildNode->GetNext();
				}
			}
			else
			{
				wxLogError(wxT("Node %s is empty"), pclsXmlNode->GetName());
			}
		}
		else
		{
			wxLogError("Node name %s is not preview settings.", pclsXmlNode->GetName());
		}
	}

	return bReturn;
}

PanelConfiguration& PanelConfiguration::operator=(const PanelConfiguration& clsObject)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	m_clsForeground = clsObject.GetForegroundColour();
	m_clsBackground = clsObject.GetBackgroundColour();
	m_clsGridround = clsObject.GetGridColour();
	m_clsPixelSize = clsObject.PixelUnitSize();

	return *this;
}


OutputConfiguration::OutputConfiguration(void)
{

}

OutputConfiguration::OutputConfiguration(const wxXmlNode* pclsXmlNode)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	FromXmlNode(pclsXmlNode);
}

OutputConfiguration::OutputConfiguration(const OutputConfiguration& clsSource)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	SetCommentType(clsSource.GetCommentType());
	SetCommentInNewline(clsSource.GetCommentInNewline());
	SetNumInline(clsSource.GetNumInLine());
}

wxXmlNode* OutputConfiguration::CreateXmlNode(void)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	wxXmlNode*				pclsNewNode = new wxXmlNode(wxXML_ELEMENT_NODE, CFG_XML_NODE_NAME_OUTPUT);
	wxXmlNode*				pclsNewChildNode;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(nullptr != pclsNewNode)
	{
		/* Data node. */
		pclsNewChildNode = new wxXmlNode(pclsNewNode, wxXML_ELEMENT_NODE, CFG_XML_NODE_NAME_OUTPUT_DATA);
		if(nullptr != pclsNewChildNode)
		{
			pclsNewChildNode->AddAttribute(wxT("num_of_line"), wxString::Format(wxT("%d"), m_iNumInLine));
		}
		/* Comment node. */
		pclsNewChildNode = new wxXmlNode(pclsNewNode, wxXML_ELEMENT_NODE, CFG_XML_NODE_NAME_OUTPUT_COMMENT);
		if(nullptr != pclsNewChildNode)
		{
			pclsNewChildNode->AddAttribute(wxT("value"), wxString::Format(wxT("%d"), m_eCommentType));
			pclsNewChildNode->AddAttribute(wxT("newline"), CGF_XML_BOOL_AS_STR(m_bNewLine));
		}
	}
	return pclsNewNode;
}

bool OutputConfiguration::FromXmlNode(const wxXmlNode* pclsXmlNode)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	wxXmlNode*				pclsChildNode;
	wxString				strReadContent;
	bool					bReturn = true;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(nullptr != pclsXmlNode)
	{
		if(pclsXmlNode->GetName().IsSameAs(CFG_XML_NODE_NAME_OUTPUT, false))
		{
			/* Start to analyze node. */
			pclsChildNode = pclsXmlNode->GetChildren();
			if(nullptr != pclsChildNode)
			{
				while(nullptr != pclsChildNode)
				{
					int iConvertValue;

					if(pclsChildNode->GetName().IsSameAs(CFG_XML_NODE_NAME_OUTPUT_DATA, false))
					{
						strReadContent = pclsChildNode->GetAttribute(wxT("num_of_line"));
						iConvertValue = _wtoi(strReadContent);
						if(iConvertValue < 0)
						{
							iConvertValue = 0;
						}
						m_iNumInLine = iConvertValue;
						DBG_LOG("Read number in line of data output is %d(xml value: %s).", iConvertValue, strReadContent);
					}
					else if(pclsChildNode->GetName().IsSameAs(CFG_XML_NODE_NAME_OUTPUT_COMMENT, false))
					{
						strReadContent = pclsChildNode->GetAttribute(wxT("value"));
						iConvertValue = _wtoi(strReadContent);
						m_eCommentType = COMMENT_TYPE(iConvertValue);
						DBG_LOG("Read setting of comment type is %d(xml value: %s).", iConvertValue, strReadContent);

						strReadContent = pclsChildNode->GetAttribute(wxT("newline"));
						m_bNewLine = CGF_XML_STR_AS_BOOL(strReadContent);
						DBG_LOG("Read setting of comment new line is %s(xml value: %s).", CGF_XML_BOOL_AS_STR(m_bNewLine), strReadContent);
					}
					else
					{
						wxLogInfo("Undefined node %s.", pclsChildNode->GetName());
					}
					pclsChildNode = pclsChildNode->GetNext();
				}
			}
			else
			{
				wxLogError(wxT("Node %s is empty"), pclsXmlNode->GetName());
			}
		}
		else
		{
			wxLogError("Node name %s is not output settings.", pclsXmlNode->GetName());
		}
	}
	return bReturn;
}

OutputConfiguration& OutputConfiguration::operator=(const OutputConfiguration& clsObject)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	m_eCommentType = clsObject.GetCommentType();
	m_bNewLine = clsObject.GetCommentInNewline();
	m_iNumInLine = clsObject.GetNumInLine();

	return *this;
}

GlobalConfiguration::GlobalConfiguration(void)
{
	/* Do nothing. */
}

GlobalConfiguration::GlobalConfiguration(const wxString& cstrFilePath)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	Load(cstrFilePath);
}

GlobalConfiguration::GlobalConfiguration(const GlobalConfiguration& clsSource)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	clsSource.CopyTo(*this);
}

void GlobalConfiguration::CopyTo(GlobalConfiguration& clsDest) const
{

	clsDest.PanelConfiguration() = m_clsPerviewCfg;
	clsDest.EncoderConfiguration() = m_clsEncoderCfg;
	clsDest.OutputConfiguration() = m_clsOutputCfg;
}

bool GlobalConfiguration::Load(const wxString& cstrFilePath)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	wxXmlDocument			clsSettingsFile(cstrFilePath);
	wxXmlNode*				pclsRootNode = clsSettingsFile.GetRoot();
	wxXmlNode*				pclsSettingsNode;
	bool					bReturn = true;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(nullptr != pclsRootNode)
	{
		DBG_LOG("Load configuration from %s.", cstrFilePath);
		if(pclsRootNode->GetName().IsSameAs(CFG_XML_NODE_NAME_CFG_ROOT, false))
		{
			/* Start to analyze node. */
			pclsSettingsNode = pclsRootNode->GetChildren();
			if(nullptr != pclsSettingsNode)
			{
				while(nullptr != pclsSettingsNode)
				{
					if(pclsSettingsNode->GetName().IsSameAs(CFG_XML_NODE_NAME_PREVIEWPANEL, false))
					{
						m_clsPerviewCfg.FromXmlNode(pclsSettingsNode);
					}
					else if(pclsSettingsNode->GetName().IsSameAs(CFG_XML_NODE_NAME_ENCORDER, false))
					{
						m_clsEncoderCfg.FromXmlNode(pclsSettingsNode);
					}
					else if(pclsSettingsNode->GetName().IsSameAs(CFG_XML_NODE_NAME_OUTPUT, false))
					{
						m_clsOutputCfg.FromXmlNode(pclsSettingsNode);
					}
					else
					{
						wxLogInfo("Undefined node %s.", pclsSettingsNode->GetName());
					}
					pclsSettingsNode = pclsSettingsNode->GetNext();
				}
			}
			else
			{
				wxLogError(wxT("Node %s is empty"), pclsRootNode->GetName());
			}
		}
		else
		{
			wxLogError("Invalid settings file, root node %s is not defined.", pclsRootNode->GetName());
		}
	}
	return bReturn;
}

bool GlobalConfiguration::Save(const wxString& cstrFilePath)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	wxXmlDocument			clsSettingsFile;
	wxXmlNode*				pclsRootNode = new wxXmlNode(wxXML_ELEMENT_NODE, CFG_XML_NODE_NAME_CFG_ROOT);
	bool					bReturn = true;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(nullptr != pclsRootNode)
	{
		pclsRootNode->AddChild(m_clsPerviewCfg.CreateXmlNode());
		pclsRootNode->AddChild(m_clsEncoderCfg.CreateXmlNode());
		pclsRootNode->AddChild(m_clsOutputCfg.CreateXmlNode());

		clsSettingsFile.SetRoot(pclsRootNode);

		bReturn = clsSettingsFile.Save(cstrFilePath);
	}
	return bReturn;
}

GlobalConfiguration& GlobalConfiguration::operator=(const GlobalConfiguration& clsObject)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	clsObject.CopyTo(*this);
	return *this;
}

ExtendedFontSettings::ExtendedFontSettings(void)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	SetToDefault();
}

ExtendedFontSettings::ExtendedFontSettings(const ExtendedFontSettings& clsSource)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	m_bForceWidth = clsSource.IsForceWidth();
	m_bCutout = clsSource.IsCutoutEnable();
	m_iCutoutHeight = clsSource.GetCutoutHeight();
	m_iForcedWidth = clsSource.GetForcedWidthValue();
	m_iOffsetX = clsSource.GetOffsetX();
	m_iOffsetY = clsSource.GetOffsetY();
}

ExtendedFontSettings::ExtendedFontSettings(const wxXmlNode* pclsXmlNode)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	LoadFromXML(pclsXmlNode);
}

void ExtendedFontSettings::SetToDefault(void)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	m_bForceWidth = false;
	m_bCutout = false;
	m_iForcedWidth = 6;
	m_iCutoutHeight = 12;
	m_iOffsetX = 0;
	m_iOffsetY = 0;
}

bool ExtendedFontSettings::LoadFromXML(const wxXmlNode* pclsXmlNode)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	wxXmlNode*				pclsChildNode;
	wxString				strReadContent;
	bool					bReturn = true;
	int						iConvertValue;
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(nullptr != pclsXmlNode)
	{
		/* Search advance setting in <Advance> node. */
		pclsChildNode = pclsXmlNode->GetChildren();
		while(nullptr != pclsChildNode)
		{
			/* Paint offset. */
			if(pclsChildNode->GetName().IsSameAs(wxT("Offset")))
			{
				/* Get horizontal offset attribute, default to 0. */
				strReadContent = pclsChildNode->GetAttribute(wxT("horizontal"), wxT("0"));
				iConvertValue = _wtoi(strReadContent);
				SetOffsetX(iConvertValue);
				DBG_LOG("Read font horizontal offset from XML data is %d(xml value: %s).", iConvertValue, strReadContent);
				/* Get vertical offset attribute, default to 0. */
				strReadContent = pclsChildNode->GetAttribute(wxT("vertical"), wxT("0"));
				iConvertValue = _wtoi(strReadContent);
				SetOffsetY(iConvertValue);
				DBG_LOG("Read font vertical offset from XML data is %d(xml value: %s).", iConvertValue, strReadContent);
			}
			/* Force width */
			if(pclsChildNode->GetName().IsSameAs(wxT("ForceWidth")))
			{
				/* Get force width enabled attribute, default to false. */
				strReadContent = pclsChildNode->GetAttribute(wxT("enable"), wxT("false"));
				if(strReadContent.IsSameAs(wxT("true"), false))
				{
					SetForceWidth(true);
				}
				else
				{
					SetForceWidth(false);
				}
				DBG_LOG("Read force width enabled from XML data is %s(xml value: %s).", IsForceWidth()?wxT("true"):wxT("false"), strReadContent);
				/* Get force width setting value, default to 4. */
				strReadContent = pclsChildNode->GetAttribute(wxT("width"), wxT("4"));
				iConvertValue = _wtoi(strReadContent);
				if(iConvertValue < 4)
				{
					iConvertValue = 4;
				}
				SetForcedWidthValue(iConvertValue);
				DBG_LOG("Read force width setting value from XML data is %d(xml value: %s).", iConvertValue, strReadContent);
			}
			pclsChildNode = pclsChildNode->GetNext();
		}
	}

	return bReturn;
}

wxXmlNode* ExtendedFontSettings::ExportToXML(void)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	wxXmlNode*				pclsAdvanceNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Advance"));
	wxXmlNode*				pclsNewChildNode;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(nullptr != pclsAdvanceNode)
	{
		/* For force width node. */
		pclsNewChildNode = new wxXmlNode(pclsAdvanceNode, wxXML_ELEMENT_NODE, wxT("ForceWidth"));
		if(nullptr != pclsNewChildNode)
		{
			pclsNewChildNode->AddAttribute(wxT("enable"), IsForceWidth()?wxT("true"):wxT("false"));
			pclsNewChildNode->AddAttribute(wxT("width"), wxString::Format(wxT("%d"), GetForcedWidthValue()));
		}
		/* For offset node. */
		pclsNewChildNode = new wxXmlNode(pclsAdvanceNode, wxXML_ELEMENT_NODE, wxT("Offset"));
		if(nullptr != pclsNewChildNode)
		{
			pclsNewChildNode->AddAttribute(wxT("horizontal"), wxString::Format(wxT("%d"), GetOffsetX()));
			pclsNewChildNode->AddAttribute(wxT("vertical"), wxString::Format(wxT("%d"), GetOffsetY()));
		}
	}

	return pclsAdvanceNode;
}

FontSettings::FontSettings(const wxString& strFontName)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
	SetSize(12);
}

FontSettings::FontSettings(const FontSettings& clsObject)
{
	SetFont(clsObject);
}

void FontSettings::SetFont(const FontSettings& clsObject)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	m_clsGeneralFontInfo = clsObject.Font();
	SetSize(clsObject.GetSize());
	m_clsExtendedFontInfo = clsObject.ExtendedInfo();
}

void FontSettings::SetFont(const wxFont& clsObject)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	m_clsGeneralFontInfo = clsObject;
	SetSize(clsObject.GetPointSize());
	m_clsExtendedFontInfo.SetToDefault();
}

void FontSettings::SetSize(int iFontSize)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	m_clsGeneralFontInfo.SetPointSize(iFontSize);
	m_clsGeneralFontInfo.SetPixelSize(wxSize(0, iFontSize));
}

int FontSettings::GetHeight(void) const
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	int 				iFontHeight;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(m_clsExtendedFontInfo.IsCutoutEnable())
	{
		iFontHeight = m_clsExtendedFontInfo.GetCutoutHeight();
	}
	else
	{
		iFontHeight = GetSize();
	}
	return iFontHeight;
}

bool FontSettings::IsBold(void) const
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	return (wxFONTWEIGHT_BOLD == m_clsGeneralFontInfo.GetWeight());
}

void FontSettings::SetBold(bool bBold)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	m_clsGeneralFontInfo.SetWeight(bBold?wxFONTWEIGHT_BOLD:wxFONTWEIGHT_NORMAL);
}

bool FontSettings::IsItalic(void) const
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	return (wxFONTSTYLE_ITALIC == m_clsGeneralFontInfo.GetStyle());
}

void FontSettings::SetItalic(bool bTialic)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	m_clsGeneralFontInfo.SetStyle(bTialic?wxFONTSTYLE_ITALIC:wxFONTSTYLE_NORMAL);
}

bool FontSettings::LoadFromXML(const wxXmlNode* pclsXmlNode)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	wxXmlNode*				pclsChildNode;
	wxString				strReadContent;
	bool					bReturn = true;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(nullptr != pclsXmlNode)
	{
		/* Start to analyze <Font> node. */
		if(pclsXmlNode->GetName().IsSameAs(wxT("Font"), false))
		{
			int iConvertValue;

			/* Read font face name from node attribute. */
			strReadContent = pclsXmlNode->GetAttribute(wxT("name"));
			SetName(strReadContent);
			DBG_LOG("Read font face name from XML data is %s.", strReadContent);

			/* Read font size from node attribute. */
			strReadContent = pclsXmlNode->GetAttribute(wxT("size"));
			iConvertValue = _wtoi(strReadContent);
			if(iConvertValue < 6)
			{
				/* Font size mast greater then 6. */
				iConvertValue = 6;
			}
			SetSize(iConvertValue);
			DBG_LOG("Read font size from XML data is %d(xml value: %s).", iConvertValue, strReadContent);
			/* Bold */
			strReadContent = pclsXmlNode->GetAttribute(wxT("bold"));
			if(strReadContent.IsSameAs(wxT("true"), false))
			{
				SetBold(true);
			}
			else
			{
				SetBold(false);
			}
			DBG_LOG("Read font bold enabled is %s(xml value: %s).", IsBold()?wxT("true"):wxT("false"), strReadContent);
			/* Italic */
			strReadContent = pclsXmlNode->GetAttribute(wxT("italic"));
			if(strReadContent.IsSameAs(wxT("true"), false))
			{
				SetItalic(true);
			}
			else
			{
				SetItalic(false);
			}
			DBG_LOG("Read font italic enabled is %s(xml value: %s).", IsItalic()?wxT("true"):wxT("false"), strReadContent);

			/* Loop for search advance font settings. */
			pclsChildNode = pclsXmlNode->GetChildren();
			while((nullptr != pclsChildNode) && (false == pclsChildNode->GetName().IsSameAs(wxT("Advance"), false)))
			{
				pclsChildNode = pclsChildNode->GetNext();
			}
			if(nullptr != pclsChildNode)
			{
				/* Search advance setting in <Advance> node. */
				m_clsExtendedFontInfo.LoadFromXML(pclsChildNode);
			}
			else
			{
				wxLogError("No advance font settings info.");
			}
		}
		else
		{
			wxLogError("Node %s is not for font settings.", pclsXmlNode->GetName());
		}
	}
	return bReturn;
}

wxXmlNode* FontSettings::ExportToXML(void)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	wxXmlNode*				pclsFontNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Font"));

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(nullptr != pclsFontNode)
	{
		/* Font node attribute. */
		pclsFontNode->AddAttribute(wxT("name"), GetName());
		pclsFontNode->AddAttribute(wxT("size"), wxString::Format(wxT("%d"), GetSize()));
		pclsFontNode->AddAttribute(wxT("bold"), IsBold()?wxT("true"):wxT("false"));
		pclsFontNode->AddAttribute(wxT("italic"), IsItalic()?wxT("true"):wxT("false"));

		/* For advance settings. */
		wxXmlNode* pclsAdvanceNode = m_clsExtendedFontInfo.ExportToXML();
		if(nullptr != pclsAdvanceNode)
		{
			pclsFontNode->AddChild(pclsAdvanceNode);
		}
	}
	return pclsFontNode;
}

FontSettings& FontSettings::operator=(const FontSettings& clsObject)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	SetFont(clsObject);

	return *this;
}

FontSettings& FontSettings::operator=(const wxFont& clsObject)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	SetFont(clsObject);

	return *this;
}

WorkSettings::WorkSettings(void)
{
	/* Set default settings. */

}

WorkSettings::WorkSettings(const wxString& cstrFilePath)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	Load(cstrFilePath);
}

WorkSettings::WorkSettings(const WorkSettings& clsSource)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	clsSource.CopyTo(*this);
}

void WorkSettings::CopyTo(WorkSettings& clsDest) const
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	clsDest.PaintFont() = m_clsPaintFont;
}

bool WorkSettings::Load(const wxString& cstrFilePath)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	wxXmlDocument			clsSettingsFile(cstrFilePath);
	wxXmlNode*				pclsRootNode = clsSettingsFile.GetRoot();
	wxXmlNode*				pclsChildNode;
	bool					bReturn = true;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(nullptr != pclsRootNode)
	{
		if(pclsRootNode->GetName().IsSameAs(CFG_XML_NODE_NAME_START_ROOT, false))
		{
			/* Start to analyze node. */
			pclsChildNode = pclsRootNode->GetChildren();
			while(nullptr != pclsChildNode)
			{
				if(pclsChildNode->GetName().IsSameAs(wxT("Font"), false))
				{
					m_clsPaintFont.LoadFromXML(pclsChildNode);
				}
				pclsChildNode = pclsChildNode->GetNext();
			}
		}
		else
		{
			wxLogInfo("Undefined root node %s.", pclsRootNode->GetName());
			bReturn = false;
		}
	}

	return bReturn;
}

bool WorkSettings::Save(const wxString& cstrFilePath)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	wxXmlDocument			clsSettingsFile;
	wxXmlNode*				pclsRootNode = new wxXmlNode(wxXML_ELEMENT_NODE, CFG_XML_NODE_NAME_START_ROOT);
	bool					bReturn = true;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(nullptr != pclsRootNode)
	{
		/* For <Font> node. */
		wxXmlNode* pclsFontNode = m_clsPaintFont.ExportToXML();
		if(nullptr != pclsFontNode)
		{
			pclsRootNode->AddChild(pclsFontNode);
		}

		clsSettingsFile.SetRoot(pclsRootNode);

		bReturn = clsSettingsFile.Save(cstrFilePath);
	}
	return bReturn;
}

WorkSettings& WorkSettings::operator=(const WorkSettings& clsObject)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	clsObject.CopyTo(*this);
	return *this;
}

GlobalConfiguration& ConfigurationInstance(void)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	static GlobalConfiguration	clsInstance;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/

	return clsInstance;
}

WorkSettings& WorkSettingsInstance(void)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	static WorkSettings			clsInstance;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/

	return clsInstance;
}
